package java_thread;

import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.locks.Lock;

/**
 * 一个使用identityHashCode避免死锁的例子
 * 摘自：https://www.cnblogs.com/hunterCecil/p/6189171.html
 * identityHashCode的作用仅仅只是排序，保证先后顺序，防止A->B,B->A的情况出现
 */
public class demo_16_lock_identityHashCode {
    private static final int NUM_THREADS = 20;
    private static final int NUM_ACCOUNTS = 5;
    private static final int NUM_ITERATIONS = 1000000;

    public static void main(String[] args) {
        final Random rdn = new Random();
        final Account[] accounts = new Account[NUM_ACCOUNTS];

        for(int i=0;i<accounts.length;i++){
            accounts[i] = new Account();
            accounts[i].setUser(String.valueOf(System.identityHashCode(accounts[i])));
        }

        class TransferThread extends Thread{
            public void run(){
                for(int i=0;i<NUM_ITERATIONS;i++){
                    int fromAccount = rdn.nextInt(NUM_ACCOUNTS);
                    int toAccount = rdn.nextInt(NUM_ACCOUNTS);

//                    TransMoney.transferMoney(accounts[fromAccount],accounts[toAccount],rdn.nextInt(1000));
                    TransMoney.transferMoney_update(accounts[fromAccount],accounts[toAccount],rdn.nextInt(1000));
                }
            }
        }

        for(int i=0;i<NUM_THREADS;i++){
            new TransferThread().start();
        }
    }
}
// 账户类：
class Account {
    private String user;
    private long account;
    public Account() {}
    public Account(String user, long account) {
        this.user = user;
        this.account = account;
    }
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }

    public long getAccount() {
        return account;
    }
    public void setAccount(long account) {
        this.account = account;
    }

    public void debit(long money){
        this.account -= money;
    }

    public void credit(long money){
        this.account += money;
    }
}
// 资产转移类：
class TransMoney {
    private static final Object tieLock = new Object();
    // 资产转移方法(可能发生死锁)：
    public static void transferMoney(Account fromAccount,Account toAccount,long amount){
        System.out.println(MessageFormat.format("开始：资产{0}从{1}转移到{2}",amount,fromAccount.getUser(),toAccount.getUser()));
        synchronized (fromAccount){
            synchronized (toAccount){
                fromAccount.debit(amount);
                toAccount.credit(amount);
                System.out.println(MessageFormat.format("完毕：资产{0}从{1}转移到{2}",amount,fromAccount.getUser(),toAccount.getUser()));
            }
        }
    }

    // 资产转移方法(identityHashCode判断并优化)：
    public static void transferMoney_update(final Account fromAccount,final Account toAccount,final long amount){
        System.out.println(MessageFormat.format("开始：资产{0}从{1}转移到{2}",amount,fromAccount.getUser(),toAccount.getUser()));
        class Helper{
            public void transfer(){
                fromAccount.debit(amount);
                toAccount.credit(amount);
                System.out.println(MessageFormat.format("完毕：资产{0}从{1}转移到{2}",amount,fromAccount.getUser(),toAccount.getUser()));
            }
        }

        int fromHash = System.identityHashCode(fromAccount);
        int toHash = System.identityHashCode(toAccount);
        if(fromHash < toHash){
            synchronized (fromAccount){
                synchronized (toAccount){
                    new Helper().transfer();
                }
            }
        }else if(fromHash > toHash){
            synchronized (toAccount){
                synchronized (fromAccount){
                    new Helper().transfer();
                }
            }
        }else{
            synchronized (tieLock){
                synchronized (fromAccount){
                    synchronized (toAccount){
                        new Helper().transfer();
                    }
                }
            }
        }
    }
}